package com.appspot.abcensys.client;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;

import com.appspot.abcensys.shared.Afwezigheid;
import com.appspot.abcensys.shared.Gebruiker;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart.PieOptions;

/**
 * Dashboard klasse om de KPI's op te vertonen.
 * 
 * @author Hugo Zonderland
 * @author Niels
 */
public class Dashboard {

	// AbcensysService
	private AbcensysServiceAsync service = (AbcensysServiceAsync) GWT.create(AbcensysService.class);

	// FlexTable
	private FlexTable flxTable, flxTableHeader;

	// Row counter
	int row;

	// Logger
	private static final Logger log = Logger.getLogger(Dashboard.class.getName());

	/**
	 * Constructor
	 */
	public Dashboard() {

		Abcensys.setLoadingImage(true);

		// row init
		row = 0;

		// Header aanmaken
		flxTableHeader = new FlexTable();
		flxTableHeader.setCellPadding(0);
		flxTableHeader.setCellSpacing(3);
		flxTableHeader.setWidth("900px");
		flxTableHeader.setStyleName("datatable");

		// Link Widget
		HTML linkWidget = new HTML("Je bent nu hier: Abcensys &raquo; Dashboard");
		linkWidget.setStyleName("lblLink");
		flxTableHeader.setWidget(row, 0, linkWidget);
		row++;

		// Image
		Image imgDashboard = new Image();
		imgDashboard.setAltText("Dashboard");
		imgDashboard.setUrl("style/icon/map.png");

		// Pagina header
		HTML h1 = new HTML("<h1> " + imgDashboard.toString() + " Dashboard</h1>");
		flxTableHeader.setWidget(row, 0, h1);

		// Row resetten
		row = 0;

		// Data table
		flxTable = new FlexTable();
		flxTable.setCellPadding(0);
		flxTable.setCellSpacing(3);
		flxTable.setWidth("900px");
		flxTable.setStyleName("datatable");

		// Haalt de huidige Gebruiker op
		service.getHuidigeGebruiker(new AsyncCallback<Gebruiker>() {
			public void onSuccess(Gebruiker gebruiker) {
				if (gebruiker == null) {
					log.info("getHuidigeGebruiker() | returnend NULL");
					Window.alert("Er ging iets mis met het ophalen van de gegevens. Probeer eens uit en in te loggen.");
				} else {
					switch (gebruiker.getType()) {
					// Docent
					case 0:
						showDashboardDocent(gebruiker);
						break;
					// Student
					case 1:
						showDashboardStudent(gebruiker);
						break;
					// Gast
					case 2:
						showDashboardGast();
						break;
					// Teamleider Personeelszaken
					case 3:
						showDashboardTeamleider(gebruiker);
						break;
					case 4:
						showDashboardManagerBedrijfsvoering(gebruiker);
						break;
					}
				}
			}

			public void onFailure(Throwable caught) {
				Window.alert("Er ging iets fout tijdens het ophalen van de gegevens. Probeer het later nog een keer.");
				log.info("Service failure -> getHuidigeGebruiker -> " + caught.getMessage());

				// Header
				RootPanel.get("content").add(flxTableHeader);

				// Data
				RootPanel.get("content").add(flxTable);

				Abcensys.setLoadingImage(false);
			}
		});
	}

	/**
	 * Laat het Dashboard voor de docent zien
	 * @param Gebruiker huidige gebruiker
	 */
	private void showDashboardDocent(final Gebruiker gebruiker) {

		Runnable onLoadCallbackPieDocent = new Runnable() {

			public void run() {

				service.getAfwezigheidVoorDocent(new AsyncCallback<TreeMap<String, ArrayList<Afwezigheid>>>() {
					public void onFailure(Throwable caught) {
						Window.alert("Er ging iets fout tijdens het ophalen van de gegevens. Probeer het later nog een keer.");
						log.info("Service failure -> getAfwezigheidVoorDocent -> " + caught.getMessage());
					}

					public void onSuccess(final TreeMap<String, ArrayList<Afwezigheid>> afwezigheidregistraties) {

						if (afwezigheidregistraties != null && !afwezigheidregistraties.isEmpty()) {

							// Iterator setten
							Set<Entry<String, ArrayList<Afwezigheid>>> set = afwezigheidregistraties.entrySet();
							Iterator<Entry<String, ArrayList<Afwezigheid>>> i = set.iterator();

							while (i.hasNext()) {
								// Entry setten
								Entry<String, ArrayList<Afwezigheid>> me = i.next();

								// vakCode setten
								final String vakCode = me.getKey();

								// Afwezigheid registraties voor de vakcode
								// setten
								final ArrayList<Afwezigheid> afwezigheden = me.getValue();

								service.getAantalGebruikersByVakcode(vakCode, new AsyncCallback<Integer>() {
									public void onFailure(Throwable caught) {
										log.info("Service failure -> getAantalGebruikersByKlascode -> " + caught.getMessage());
									}

									public void onSuccess(Integer aantalStudenten) {
										// Pie init
										pieInit(aantalStudenten, afwezigheden, vakCode);
									}
								});
							}
						} else {
							flxTable.setWidget(row, 0, new Label("Er zijn geen afwezigheidregistraties bekend."));
						}
					}

					private void pieInit(int aantalStudenten, ArrayList<Afwezigheid> afwezigheidregistraties, String vakCode) {

						if (!afwezigheidregistraties.isEmpty()) {
							// Wanneer niet leeg, PieChart aanmakne
							PieChart pie = new PieChart(createTable(afwezigheidregistraties, aantalStudenten), createOptions());
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, pie);
							row++;
						} else {
							// Melding plaatsen
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, new Label("Geen afwezigheidsregistraties bekend"));
							row++;
						}
						flxTable.setWidget(row, 0, new HTML("<hr />"));
						flxTable.setWidget(row, 1, new HTML("<hr />"));
						row++;
					}

					/**
					 * Creeert de DataTable voor de PieChart
					 * 
					 * @param ArrayList
					 *            <Afwezigheid> alle afwezigheidsregistraties
					 *            die bij de les horen
					 * @return AbstractDataTable gecreeerde DataTable
					 */
					private AbstractDataTable createTable(ArrayList<Afwezigheid> afwezigheden, int aantalStudenten) {
						DataTable data = DataTable.create();
						data.addColumn(ColumnType.STRING, "Aantal registraties");
						data.addColumn(ColumnType.NUMBER, "Registraties");
						data.addRows(2);
						data.setValue(0, 0, "Afwezigen");
						data.setValue(0, 1, afwezigheden.size());
						data.setValue(1, 0, "Aanwezigen");
						data.setValue(1, 1, aantalStudenten - afwezigheden.size());

						return data;
					}

					/**
					 * Creeert de opmaak van de PieChart
					 * 
					 * @param String
					 *            met de Vakcode waar de PieChart word
					 *            aangemaakt
					 * @return PieOptions gecreeerde PieOptions
					 */
					private PieOptions createOptions() {
						PieOptions options = PieOptions.create();
						options.setWidth(400);
						options.setHeight(240);
						options.set3D(true);

						return options;
					}
				});
			}
		};
		// Laad de PieChart
		VisualizationUtils.loadVisualizationApi(onLoadCallbackPieDocent, PieChart.PACKAGE);

		// Header table
		RootPanel.get("content").add(flxTableHeader);

		// Data table
		RootPanel.get("content").add(flxTable);

		Abcensys.setLoadingImage(false);
	}

	/**
	 * Laat het Dashboard zien voor de Student
	 * 
	 * @param Gebruiker
	 *            de huidige gebruiker
	 */
	private void showDashboardStudent(final Gebruiker gebruiker) {

		Runnable onLoadCallbackPieStudent = new Runnable() {

			public void run() {

				flxTable.setWidget(row, 0, new Label("Hieronder staan jou afwezigheidsregistraties per vak afgebeeld."));
				row++;

				service.getAfwezigheidVoorStudentDashboard(new AsyncCallback<TreeMap<String, ArrayList<Afwezigheid>>>() {
					public void onFailure(Throwable caught) {
						Window.alert("Er ging iets fout tijdens het ophalen van de gegevens. Probeer het later nog een keer.");
						log.info("Service failure -> getAfwezigheidVoorStudentDashboard -> " + caught.getMessage());
					}

					public void onSuccess(TreeMap<String, ArrayList<Afwezigheid>> results) {

						if (results != null && !results.isEmpty()) {
							// Iterator setten
							Set<Entry<String, ArrayList<Afwezigheid>>> set = results.entrySet();
							Iterator<Entry<String, ArrayList<Afwezigheid>>> i = set.iterator();

							while (i.hasNext()) {
								// Entry setten
								Entry<String, ArrayList<Afwezigheid>> me = i.next();

								// Les setten
								final String vakCode = me.getKey();

								// Afwezigheid registraties voor de vakcode
								// setten
								final ArrayList<Afwezigheid> afwezigheden = me.getValue();

								service.getTotaalAantalLessenByKlasAndVakcode(gebruiker.getKlasCode(), vakCode, new AsyncCallback<Integer>() {
									public void onFailure(Throwable caught) {
										log.info("Service failure -> getAantalGebruikersByKlascode -> " + caught.getMessage());
									}

									public void onSuccess(Integer aantalLessen) {
										pieInit(aantalLessen, afwezigheden, vakCode);
									}
								});
							}
						} else {
							flxTable.setWidget(row, 0, new Label("Er zijn geen afwezigheidregistraties bekend."));
						}
					}

					private void pieInit(int aantalLessen, ArrayList<Afwezigheid> afwezigheidregistraties, String vakCode) {
						if (afwezigheidregistraties != null && !afwezigheidregistraties.isEmpty()) {
							PieChart pie = new PieChart(createTable(afwezigheidregistraties, aantalLessen), createOptions());
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, pie);
							row++;
						} else {
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, new Label("Geen afwezigheidsregistraties bekend"));
							row++;
						}
						flxTable.setWidget(row, 0, new HTML("<hr />"));
						flxTable.setWidget(row, 1, new HTML("<hr />"));
						row++;
					}

					/**
					 * Creeert de DataTable voor de PieChart
					 * 
					 * @param ArrayList
					 *            <Afwezigheid> alle afwezigheidsregistraties
					 *            die bij de les horen
					 * @return AbstractDataTable gecreeerde DataTable
					 */
					private AbstractDataTable createTable(ArrayList<Afwezigheid> afwezigheden, Integer aantalLessen) {
						DataTable data = DataTable.create();
						data.addColumn(ColumnType.STRING, "Aantal registraties");
						data.addColumn(ColumnType.NUMBER, "Registraties");
						data.addRows(2);
						data.setValue(0, 0, "Lessen");
						data.setValue(0, 1, aantalLessen);
						data.setValue(1, 0, "Afwezig");
						data.setValue(1, 1, afwezigheden.size());

						return data;
					}

					/**
					 * Creeert de opmaak van de PieChart
					 * 
					 * @param String
					 *            met de Vakcode waar de PieChart word
					 *            aangemaakt
					 * @return PieOptions gecreeerde PieOptions
					 */

					private PieOptions createOptions() {
						PieOptions options = PieOptions.create();
						options.setWidth(400);
						options.setHeight(240);
						options.set3D(true);

						return options;
					}
				});
			}
		};

		// Laad de PieChart
		VisualizationUtils.loadVisualizationApi(onLoadCallbackPieStudent, PieChart.PACKAGE);

		// Header table
		RootPanel.get("content").add(flxTableHeader);

		// Data table
		RootPanel.get("content").add(flxTable);

		Abcensys.setLoadingImage(false);
	}

	/**
	 * Default Dashboard
	 */
	private void showDashboardGast() {
		flxTable.setWidget(row, 0, new Label("Klik hierboven op \"Inloggen\" om in te loggen om dit systeem te gebruiken."));

		// Header table
		RootPanel.get("content").add(flxTableHeader);

		// Data table
		RootPanel.get("content").add(flxTable);

		Abcensys.setLoadingImage(false);
	}

	/**
	 * Laat het Dashboard zien voor de TeamLeider
	 * 
	 * @param Gebruiker
	 *            met de huidige Gebruiker
	 */
	private void showDashboardTeamleider(Gebruiker gebruiker) {

		Runnable onLoadCallbackPieTeamleider = new Runnable() {

			public void run() {

				service.getAlleAfwezigheidPerVak(new AsyncCallback<TreeMap<String, ArrayList<Afwezigheid>>>() {

					public void onFailure(Throwable caught) {
						Window.alert("Er ging iets fout tijdens het ophalen van de gegevens. Probeer het later nog een keer.");
						log.info("Service failure -> getAfwezigheidVoorDocent -> " + caught.getMessage());
					}

					public void onSuccess(TreeMap<String, ArrayList<Afwezigheid>> results) {
						if (results != null && !results.isEmpty()) {

							// Iterator setten
							Set<Entry<String, ArrayList<Afwezigheid>>> set = results.entrySet();
							Iterator<Entry<String, ArrayList<Afwezigheid>>> i = set.iterator();

							while (i.hasNext()) {
								// Entry setten
								Entry<String, ArrayList<Afwezigheid>> me = i.next();

								// Les setten
								final String vakCode = me.getKey();

								// Afwezigheid registraties voor de vakcode
								// setten
								final ArrayList<Afwezigheid> afwezigheden = me.getValue();

								service.getAantalGebruikersByVakcode(vakCode, new AsyncCallback<Integer>() {
									public void onFailure(Throwable caught) {
										log.info("Service failure -> getAantalGebruikersByKlascode -> " + caught.getMessage());
									}

									public void onSuccess(Integer aantalStudenten) {
										pieInit(aantalStudenten, afwezigheden, vakCode);
									}
								});
							}
						} else {
							flxTable.setWidget(row, 0, new Label("Er zijn geen afwezigheidregistraties bekend."));
						}
					}

					private void pieInit(int aantalStudenten, ArrayList<Afwezigheid> afwezigheidregistraties, String vakCode) {
						if (!afwezigheidregistraties.isEmpty()) {
							PieChart pie = new PieChart(createTable(afwezigheidregistraties, aantalStudenten), createOptions());
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, pie);
							row++;
						} else {
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, new Label("Geen afwezigheidsregistraties bekend"));
							row++;
						}
						flxTable.setWidget(row, 0, new HTML("<hr />"));
						flxTable.setWidget(row, 1, new HTML("<hr />"));
						row++;
					}

					/**
					 * Creeert de DataTable voor de PieChart
					 * 
					 * @param ArrayList
					 *            <Afwezigheid> alle afwezigheidsregistraties
					 *            die bij de les horen
					 * @return AbstractDataTable gecreeerde DataTable
					 */
					private AbstractDataTable createTable(ArrayList<Afwezigheid> afwezigheden, int aantalStudenten) {
						DataTable data = DataTable.create();
						data.addColumn(ColumnType.STRING, "Aantal registraties");
						data.addColumn(ColumnType.NUMBER, "registraties");
						data.addRows(2);
						data.setValue(0, 0, "Afwezigen");
						data.setValue(0, 1, afwezigheden.size());
						data.setValue(1, 0, "Aanwezigen");
						data.setValue(1, 1, aantalStudenten - afwezigheden.size());

						return data;
					}

					/**
					 * Creeert de opmaak van de PieChart
					 * 
					 * @param String
					 *            met de Vakcode waar de PieChart word
					 *            aangemaakt
					 * @return PieOptions gecreeerde PieOptions
					 */
					private PieOptions createOptions() {
						PieOptions options = PieOptions.create();
						options.setWidth(400);
						options.setHeight(240);
						options.set3D(true);

						return options;
					}
				});
			}
		};

		// Laad de PieChart
		VisualizationUtils.loadVisualizationApi(onLoadCallbackPieTeamleider, PieChart.PACKAGE);

		// Header table
		RootPanel.get("content").add(flxTableHeader);

		// Data table
		RootPanel.get("content").add(flxTable);

		Abcensys.setLoadingImage(false);
	}

	/**
	 * Dashboard voor de Manager Bedrijfsvoering
	 * 
	 * @param Gebruiker
	 *            huidige Gebruiker
	 */
	private void showDashboardManagerBedrijfsvoering(Gebruiker gebruiker) {

		Runnable onLoadCallbackPieManagerBedrijfsvoering = new Runnable() {

			public void run() {
				service.getAfwezigheidPerInstituut(new AsyncCallback<TreeMap<String, TreeMap<Integer, Integer>>>() {
					public void onFailure(Throwable caught) {
						log.info("Service failure -> getAfwezigheidPerInstituut -> " + caught.getMessage());
						Window.alert("Er ging iets fout met het ophalen van de gegevens, probeer het later nog een keer.");
					}

					public void onSuccess(TreeMap<String, TreeMap<Integer, Integer>> results) {
						if (results != null && !results.isEmpty()) {

							// Iterator setten
							Set<Entry<String, TreeMap<Integer, Integer>>> set = results.entrySet();
							Iterator<Entry<String, TreeMap<Integer, Integer>>> i = set.iterator();

							while (i.hasNext()) {
								// Entry setten
								Entry<String, TreeMap<Integer, Integer>> me = i.next();

								// Les setten
								final String vakCode = me.getKey();

								// Afwezigheid registraties voor de vakcode
								// setten
								TreeMap<Integer, Integer> afaanwezigen = me.getValue();
								
								// Iterator setten
								Set<Entry<Integer, Integer>> setRegistraties = afaanwezigen.entrySet();
								Iterator<Entry<Integer, Integer>> iRegistraties = setRegistraties.iterator();
								
								while (iRegistraties.hasNext()) {
									// Entry setten
									Entry<Integer, Integer> meRegistraties = iRegistraties.next();
									
									// Waarden setten
									final int afwezigen = meRegistraties.getKey();
									final int aanwezigen = meRegistraties.getValue();
									
									// PieInit
									pieInit(afwezigen, aanwezigen, vakCode);
								}
							}
						} else {
							flxTable.setWidget(row, 0, new Label("Er zijn geen afwezigheidregistraties bekend."));
						}
					}

					private void pieInit(int afwezigen, int aanwezigen, String vakCode) {
						if (aanwezigen > 0) {
							PieChart pie = new PieChart(createTable(afwezigen, aanwezigen), createOptions());
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, pie);
							row++;
						} else {
							Label lblHeader = new Label(vakCode);
							lblHeader.setStyleName("h1");
							flxTable.setWidget(row, 0, lblHeader);
							flxTable.setWidget(row, 1, new Label("Geen afwezigheidsregistraties bekend"));
							row++;
						}
						flxTable.setWidget(row, 0, new HTML("<hr />"));
						flxTable.setWidget(row, 1, new HTML("<hr />"));
						row++;
					}

					/**
					 * Creeert de DataTable voor de PieChart
					 * 
					 * @param ArrayList
					 *            <Afwezigheid> alle afwezigheidsregistraties
					 *            die bij de les horen
					 * @return AbstractDataTable gecreeerde DataTable
					 */
					private AbstractDataTable createTable(int afwezigen, int aanwezigen) {
						DataTable data = DataTable.create();
						data.addColumn(ColumnType.STRING, "Aantal registraties");
						data.addColumn(ColumnType.NUMBER, "registraties");
						data.addRows(2);
						data.setValue(0, 0, "Afwezigen");
						data.setValue(0, 1, afwezigen);
						data.setValue(1, 0, "Aanwezigen");
						data.setValue(1, 1, aanwezigen - afwezigen);

						return data;
					}

					/**
					 * Creeert de opmaak van de PieChart
					 * 
					 * @param String
					 *            met de Vakcode waar de PieChart word
					 *            aangemaakt
					 * @return PieOptions gecreeerde PieOptions
					 */
					private PieOptions createOptions() {
						PieOptions options = PieOptions.create();
						options.setWidth(400);
						options.setHeight(240);
						options.set3D(true);

						return options;
					}
				});
			}
		};

		// Laad de PieChart
		VisualizationUtils.loadVisualizationApi(onLoadCallbackPieManagerBedrijfsvoering, PieChart.PACKAGE);

		// Header table
		RootPanel.get("content").add(flxTableHeader);

		// Data table
		RootPanel.get("content").add(flxTable);

		Abcensys.setLoadingImage(false);
	}
}
